/**
 * Zoomify
 * A jQuery plugin for simple lightboxes with zoom effect.
 * http://indrimuska.github.io/zoomify
 *
 * (c) 2015 Indri Muska - MIT
 */
;(function ($) {

    // initialization
    Zoomify = function (element, options) {
        var that = this;

        this._zooming = false;
        this._zoomed = false;
        this._timeout = null;
        this.$shadow = null;
        this.$image = $(element).addClass('zoomify');
        this.options = $.extend({}, Zoomify.DEFAULTS, this.$image.data(), options);

        this.$image.on('click', function () {
            that.zoom();
        });
        $(window).on('resize', function () {
            that.reposition();
        });
        $(document).on('scroll', function () {
            that.reposition();
        });
    };
    Zoomify.DEFAULTS = {
        duration: 200,
        easing: 'linear',
        scale: 0.9
    };

    // css utilities
    Zoomify.prototype.transition = function ($element, value) {
        $element.css({
            '-webkit-transition': value,
            '-moz-transition': value,
            '-ms-transition': value,
            '-o-transition': value,
            'transition': value
        });
    };
    Zoomify.prototype.addTransition = function ($element) {
        this.transition($element, 'all ' + this.options.duration + 'ms ' + this.options.easing);
    };
    Zoomify.prototype.removeTransition = function ($element, callback) {
        var that = this;

        clearTimeout(this._timeout);
        this._timeout = setTimeout(function () {
            that.transition($element, '');
            if ($.isFunction(callback)) callback.call(that);
        }, this.options.duration);
    };
    Zoomify.prototype.transform = function (value) {
        this.$image.css({
            '-webkit-transform': value,
            '-moz-transform': value,
            '-ms-transform': value,
            '-o-transform': value,
            'transform': value
        });
    };
    Zoomify.prototype.transformScaleAndTranslate = function (scale, translateX, translateY, callback) {
        this.addTransition(this.$image);
        this.transform('scale(' + scale + ') translate(' + translateX + 'px, ' + translateY + 'px)');
        this.removeTransition(this.$image, callback);
    };

    // zooming functions
    Zoomify.prototype.zoom = function () {
        if (this._zooming) return;

        if (this._zoomed) this.zoomOut();
        else this.zoomIn();
    };
    Zoomify.prototype.zoomIn = function () {
        var that = this,
            transform = this.$image.css('transform');

        this.transition(this.$image, 'none');
        this.transform('none');

        var offset = this.$image.offset(),
            width = this.$image.outerWidth(),
            height = this.$image.outerHeight(),
            nWidth = this.$image[0].naturalWidth || +Infinity,
            nHeight = this.$image[0].naturalHeight || +Infinity,
            wWidth = $(window).width(),
            wHeight = $(window).height(),
            scaleX = Math.min(nWidth, wWidth * this.options.scale) / width,
            scaleY = Math.min(nHeight, wHeight * this.options.scale) / height,
            scale = Math.min(scaleX, scaleY),
            translateX = (-offset.left + (wWidth - width) / 2) / scale,
            translateY = (-offset.top + (wHeight - height) / 2 + $(document).scrollTop()) / scale;

        this.transform(transform);

        this._zooming = true;
        this.$image.addClass('zoomed').trigger('zoom-in.zoomify');
        setTimeout(function () {
            that.addShadow();
            that.transformScaleAndTranslate(scale, translateX, translateY, function () {
                that._zooming = false;
                that.$image.trigger('zoom-in-complete.zoomify');
            });
            that._zoomed = true;
        });
    };
    Zoomify.prototype.zoomOut = function () {
        var that = this;

        this._zooming = true;
        this.$image.trigger('zoom-out.zoomify');
        this.transformScaleAndTranslate(1, 0, 0, function () {
            that._zooming = false;
            that.$image.removeClass('zoomed').trigger('zoom-out-complete.zoomify');
        });
        this.removeShadow();
        this._zoomed = false;
    };

    // page listener callbacks
    Zoomify.prototype.reposition = function () {
        if (this._zoomed) {
            this.transition(this.$image, 'none');
            this.zoomIn();
        }
    };

    // shadow background
    Zoomify.prototype.addShadow = function () {
        var that = this;
        if (this._zoomed) return;

        if (that.$shadow) that.$shadow.remove();
        this.$shadow = $('<div class="zoomify-shadow"></div>');
        $('body').append(this.$shadow);
        this.addTransition(this.$shadow);
        this.$shadow.on('click', function () {
            that.zoomOut();
        })

        setTimeout(function () {
            that.$shadow.addClass('zoomed');
        }, 10);
    };
    Zoomify.prototype.removeShadow = function () {
        var that = this;
        if (!this.$shadow) return;

        this.addTransition(this.$shadow);
        this.$shadow.removeClass('zoomed');
        this.$image.one('zoom-out-complete.zoomify', function () {
            if (that.$shadow) that.$shadow.remove();
            that.$shadow = null;
        });
    };

    // plugin definition
    $.fn.zoomify = function (option) {
        return this.each(function () {
            var $this = $(this),
                zoomify = $this.data('zoomify');

            if (!zoomify) $this.data('zoomify', (zoomify = new Zoomify(this, typeof option == 'object' && option)));
            if (typeof option == 'string' && ['zoom', 'zoomIn', 'zoomOut', 'reposition'].indexOf(option) >= 0) zoomify[option]();
        });
    };

})(jQuery);